I decided to make a little tip collection for everyone out there who wants to script better.

This isn't a tutorial for newbies because I didn't explain all the commands I've used here; and don't intend to.

If you want to have a script that works better, here are some tips to improve its performance.

 

Neat Scripting

 

The first step is to learn how to write the script correctly and efficiently.

 

* Don't use excessive Braces { } where you don't need them, and you only need them when there's more then one line in the command.

   The { Brace means "Begin" and the } Brace means "End" so if there's only one line to the event or command, you don't need to give the script a beginning and end command.

  For example:

 

ON *:text:*:*: { if ($nick = Blah) { do something here } }

Which the scrip reads like this: ON *:text:*:*: Begin-event if ($nick = Blah) Begin-if do something here End-if End-event

 

So as you see, you don't need to tell it where to begin and end if there's only one line.

So this would better:

 

ON *:text:*:*: if ($nick = Blah) do something here

 

Now besides the fact that it's useless to put excessive Braces, they all use more CPU.

That's because the { Begin Brace is actually a command that calls a procedure to check for the } End Brace (and run all the commands between of course).

It doesn't take a lot of CPU of course, but it's about the same amount as calling an alias (see "Saving CPU/memory usage").

 

 

* If you are making aliases that call stuff so you want have to write a lot of code, then do it right.

   Here's an example from an MDX tutorial I've read somewhere:

alias -l mdx { return $+(",$scriptdir,mdx.dll,") }

alias -l Views { return $+($scriptdir,Views.mdx) }

dll $mdx SetControlMDX Dialog ID ListView Style > $views

 

Now as you can see in the end you still have to use the /dll command with both aliases, and add the > prefix there.

So if you think about it, you could add these commands to your aliases and make them call each other :

Alias -l mdx { dll $+(",$scriptdir,mdx.dll,") $1- }

Alias -l views { mdx $1- > $+($scriptdir,views.mdx) }

views SetControlMDX Dialog ID ListView Style

 

This way you can save yourself a lot of writing, and it will look more organized.

 

* One $+ is enough, looks much better and you can add whatever you want with a comma :

   notice $nick <> Account created: ftp:// $+ $nick $+ : $+ $iif($2,$2,%ftp.defaultpass) $+ @ $+ %ftp.server $+ : $+ %ftp.port $+ / <>

   notice $nick <> Account created: $+(ftp://,$nick,:,$iif($2,$2,%ftp.defaultpass),@ ,%ftp.server,:,%ftp.port,/ <>)

 

* Use %vars that have meaning, so you can return after a few weeks and remember what each %var contains.

   Look at the next tip for a good example… Why not call that %cc variable %result ? or just %channels ?

 

* Don't use the | separator ! It can get very confusing if you  look back at the script a month from now. Every command should have its own line:

   Alias com-chan { if ($1) { var %a = $comchan($1,0) | if (%a > 0) { while ($comchan($1,%a)) { .var %cc = $addtok(%cc, $comchan($1,%a), 44) | dec %a } echo $nick Common Channels: %cc } } | else { return } }

   This looks like a mess, and in a few weeks it will be pretty hard to follow.

   Here's a better way of scripting it:

Alias com-chan {

  if ($1) {

    var %a = $comchan($1,0)

    If (%a > 0) {

      while ($comchan($1,%a)) {

        var %cc = $addtok(%cc, $comchan($1,%a), 44)

        dec %a

      }

      echo $nick Common Channels: %cc

    }

  }

  else { return }

}

                   

* Don't use generalized events like ON *:text:*:*: if you don't have to. Try to at least pin point it to specific match text or location like ON *:text:*:?:

   It's a waste of resources for the event to work and process its lines, where there's no chance for it to work.

 

* Use the level prefixes to prevent events from working where they're not needed:

  On me:*:Join:*: Echo –a This works when you join any channel

  On !*:Join:*: Echo –a This works when anyone but you joins the channel

  On @*:Join:*: Echo –a This works when you're oped on the channel someone just joined.

 

 Just remember that Events work like If-Else statements, if you have more then one event of the same type in the same file, the script will run through them by their order, and if the first event triggers, it will halt all other events of the same type.

 

  On *:text:*:*: echo –a yeap

  On *:text:*check*:*: echo –a test

 

 The second event won't run even if the word "Check" is in the line. But if the second line would come first:

 

  On *:text:*check*:*: echo –a test

  On *:text:*:*: echo –a yeap

 

 The second event will trigger if the word "Check" doesn't appear in the text.

 

* Keep your script organized. Keep event types and aliases together, and try to sort on a way that you will remember, I would suggest alphabetical order.

  The order in a script is very important for you to keep track of what's going on while the script gets bigger and messier.

   Using ;Comments is a good advice to help you read the script.

   For example:

 

 ;Raw

 raw *:*: echo -s $numeric $1- 

 

 ;CTCP

 ctcp *:*:*: Echo -a CTCP $1-

 

 ;Events

 on *:conenct:

 on *:kick:#:

 on *:open:?:

 on *:text:*:*:

 on *:quit:

 

 ;Dialogs

 ;Dialog Test

 Dialog Test {

 

 }

 on *:dialog:Test:init:*:

 on *:dialog:Test:iclose:*:

 on *:dialog:Test:sclick:*:

 

 ;Aliases

 

 Alias –l Blah

 Alias –l Something

 Alias –l Test

 

  You see, it can look a lot nicer, and you will be able to go through your script easily even while it bigger and bigger.

 

Addon Tips

 

When you make an addon, remember that there are probably other scripts loaded. You need to follow some simple rules, so it won't interfere with the other scripts.

 

* Try to avoid using the /halt command in your custom aliases.

   The /halt command will not only halt the current alias, but the entire parent event that called it.

   Unless you know what you're doing, and you really intend to stop all the processes of that event, just use /return command instead.

 

* You can try using the ! prefix when calling a default command to make sure it calls mIRC's default command and not an alias:

   For example:

   !join #channel

   !notice Nick blah

 

* Use only local variables with the /var command instead of /set or just %var = value.

   Remember that if the user has a full script,  it might have used most of the common variable names you would like to use.

   Because of this, remember to create the variable before you do a Boolean check on it, example:

   Alias Blah {

     Var %check

     If ($1 = blah) var %blah = yeap

     If (!%check) return nope

     Else yeap

   }

   You can see here: the variable %blah in the beginning, so the script will use this local variable. If I didn't set it up, and $1 wasn't equal to "blah" it would have checked if there's a global variable called %check.

 

* If you want to set any global setting that will be saved for further use, then you can always use .ini files, to store data, and Hash tables, if it's only temporary.

 

 

Saving CPU/ Memory usage

 

Saving CPU and memory usage is only relevant when you have really long loops, or have events that you know that are going process a lot of data, like ON TEXT events.

You won't notice most of these tips if you don't have any time consuming loops or events.

The best way to check yourself, is to make a loop that will repeat itself about 10000 times, and in it try all sorts of ways to do what you want, and then see how many ticks it takes for the loop to finish. Ex:

Alias Test {

   Var %ticks = $ticks

   Var %a = 1

   While (%a < 10000) {

       ;The method you're checking comes here

   }

   Echo –a $calc($ticks - %ticks)

}

Just remember that 1000 ticks are equal to about 1 second.

 

* When using multiple arguments in an IF sentence, it would be good to sort them in a logical order.

  This is because the IF sentence evaluates the arguments from left to right.

  So, if for example you have an IF sentence with multiple arguments using the AND (&&) operator:

  IF (Blah isin %check) && (/msg isin %check)

  And you know that the most important thing to check is if the command /msg is in the line %check then it's better to put the /msg argument first, and if it doesn't exist the script will move on:

  IF (/msg isin %check) && (Blah isin %check)  

  This kind of logic is good for arguments of the same kind, but if you have a more CPU consuming argument, like a $read(file.txt,w,*blah*) , you should leave it to the end, even if it's more "important" logically.

  You don't want the script to run too many CPU consuming $identifiers or aliases if there's another simpler argument that could rule them out and stop the processing of the IF statement.

 

 

* Don't give the same argument twice in an IF-ELSE sentence if it can be assumed from the first argument, ex:

   If ($4) && ($5) { }

   Elseif (!$5) { }

   In the first IF sentence you don't need to check if $4 exists, because if $5 exists we can assume there's a $4.

   And in the second line, you don't have to check if $5 doesn't exist, because if the first line fails then you can assume that $5 doesn't exist.

   So this would be better scripted like this:

   If ($5) { }

   Else { }

   Just remember that every calculation and every argument uses resources.

 

* Combine similar IF-Else sentences if you are trying to evaluate similar sentences or data. Here's an example:

   var %format = Hi*there*

   if (%format iswm $1-) return 1

   var %format = Hi my name is*how*everyone*

   if (%format iswm $1-)  return 2

   var %format = Hi*everyone*

   if (%format iswm $1-)  return 3

   var %format = Hello*everyone*

   if (%format iswm $1-)  return 4

   You can see that there are a few words that repeat in these lines, these are: Hi , Hello, and everyone.

    So, instead of making the script go through all the line formats, it would be better to group them into groups, with similar matches, so it will have less arguments to calculate.

  Remember that it's easier for the script to check a certain item in the text then searching for a wildmatch.

   If ($1 = Hi) {

     var %format = *there*

     if (%format iswm $2-) return 1

     var %format = Hi my name is*how*everyone*

     if (%format iswm $2-)  return 2

     var %format = Hi*everyone*

     if (%format iswm $2-)  return 3

   }

   var %format = Hello*everyone*

   if (%format iswm $1-)  return 4

   Now the script does exactly the same thing, but now if the sentence doesn't start with the word Hi, it won't evaluate all the arguments that have that word.

   Notice that because I've already checked the first word, all the other if sentences try to match the rest of text from the second word.

 

* Regular expression lines are much harder for the CPU then regular Wild Match expressions.

   If you are searching for a certain line or match in an ON TEXT event, it would be better to use regular "if" sentences with iswm and isin rather then a $regex expression.

   After you've found the match, you could start using $regex expression to get the data you want from the line. But the time and CPU consuming work is matching the text in the ON TEXT event.

   I gave the ON TEXT event as an example of a loop that works constantly on almost every line received from the server

 

*   Avoid putting in unnecessary calculations. Here's an example of a size calculator that calculates file sizes from Mb, Kb etc. to bytes:

      $calc($replace($remove($1,b),k,* 1024,m,* 1024 ^2,g,* 1024 ^3))

     Although this looks very nice and easy, it still needs to calculate 1024 ^2 and 1024 ^3 every time it calculates Mb or Gb values.

     This can start to show its effects when you have a very long loop, like searching a directory, or a dialog list.

     It is better to evaluate them yourself, and save the computer some time and effort:

      $calc($replace($remove($1,b),k,* 1024,m,* 1048576,g,* 1073741824))

 

* Sometimes it's better to use a regular loop and a regular If (V1 iswm V2) sentence, rather than looping through certain $identifiers that have Wildmatch options in them.

   The best way to explain this is by an example using $hget to find certain items in a HASH table.

   For example, look at both these loops:

 

Var %a = 1

while ($hfind(HashTable,*wildcard*,%a,w)) {  

  ;Do stuff here

  inc %a

}

 

Var %a = 1

while ($hget(HashTable,%a).item) {

  var %item = $v1

  if (*wildcard* iswm %item) {

    ;Do stuff here

  }

  inc %a

}

 

  Although the first loop looks much neater and exploits the $hfind identifier to find you all the matching items, it will still take about twice as much time to resolve.

  That happens because the $hfind identifier tries each time to find the next matching item, but it starts each time from the beginning of the Hash table. So if you have a lot of items that match the wildcard it will go over the the entire Hash table over and over.

  But the second loop will just go over the Hash table once, and find all the matches. 

 

 * Try not to use $identifiers in a while loop's argument. If you know that the $identifier will return a constant value that won't be changed in the loop's process then it's better to set the $identifiers value to a %variable, and then use the %variable as the argument.

    That's because the loop will evaluate the $identifier on each run to check if the value hasn't changed.

    Just to show you how much CPU you can change:

Alias test {

  var %ticks = $ticks

  var %a = 1

  while (%a < $lines(servers.ini)) {

    inc %a

  }

  echo -a $calc($ticks - %ticks)

}

 

This little alias will take 1297 ticks (my servers.ini has 976 lines)

But if I'd put the $lines value in a %variable, and use the %variable in the argument:

Alias test {

  var %ticks = $ticks

  var %a = 1

  var %lines = $lines(servers.ini)

  while (%a < %lines) {

    inc %a

  }

  echo -a $calc($ticks - %ticks)

}

 

This takes only 16 ticks to process. And that's because it doesn't have to process the $lines identifier 976 times.

 

 

*  Don't hesitate to store data that you get from $identifiers into variables. mIRC $identifiers and aliases are little procedures that calculate things, and return the data you requested. But each time you call it, it recalculates.

    Reading from files takes a lot of CPU usage too, so if you are reading the same thing, or different parts of the same line, it would be better to store it in a %var.

    For an example, here's something that reads settings from the mirc.ini file:

    if ($gettok($readini(mirc.ini,options,n7),2,44) = 1) { do stuff }

    if ($gettok($readini(mirc.ini,options,n7),3,44) = 1) { do stuff }

    if ($gettok($readini(mirc.ini,options,n7),16,44) = 1) { do stuff }

    if ($gettok($readini(mirc.ini,options,n7),19,44) = 1) { do stuff }

  

   Now if it would be on an On Dialog Init event, that wouldn't be too bad because it only loads once. But it would still be better to read from the file once, and then evaluate that line over and over:

    Var %line = $readini(mirc.ini,options,n7) 

    if ($gettok(%line,2,44) = 1) { do stuff }

    if ($gettok(%line,3,44) = 1) { do stuff }

    if ($gettok(%line,16,44) = 1) { do stuff }

    if ($gettok(%line,19,44) = 1) { do stuff }

 

* Dialog lists are very slow. If you have a very large list that needs to be listed, or filtered, list it in a @window first and then filter it back to the dialog's list.

  Although it might sound strange because you're actually listing it twice, it's faster.

  For an example, make a dialog called test:

Dialog Test {

  Size -1 -1 380 200

  Option dbu

  List 2, 10 32 120 160, size sort

  Button "OK", 1, 285 180 42 13, ok, default

}

 

Now try the 2 ways, we'll calculate the amount of Ticks (1000 ticks = about 1 sec) that pass from the beginning of the alias to the end…

Try the /did –a line:

 

alias test {

  var %ticks = $ticks

  var %b = 1

  While (%b < 10000) {

    Did -a test 2 Test This $+ %b

    Inc %b

  }

  echo -a $calc($ticks - %ticks)

}

 

Load the dialog (/dialog –m Test Test) and then type /test … I got 1078 Ticks

Now lets try the other way:

alias test2 {

  var %ticks = $ticks

  window -h @test

  var %b = 1

  While (%b < 10000) {

    aline @test Test This $+ %b

    Inc %b

  }

  filter -o @test test 2

  close -@ @test

  echo -a $calc($ticks - %ticks)

}

 

Load the dialog (/dialog –m Test Test) and then type /test2 … I got 515 Ticks

So we can clearly see that this method is twice as fast, although we've opened a hidden window, listed into it, then copied all that is in that window to the dialog with the /filter command, and then closed the window.

Now if you want to use /filters with your dialog it would be the same, and it's actually better to filter the list to a @window and then back again, than filtering the list to itself.

I'd advise to have a hidden window that has the same information as the list has, and then filter that window into the dialog.

 

* You should remember that calling aliases is also time consuming and can use up your CPU.

   I'm not saying you shouldn't use aliases, but you could take in mind that you don't have to use a lot of little one lined aliases in your script if you want to reduce the time it takes to process you script.

Here's an example, I'll do exactly the same thing, but I'll add aliases to call some of the commands:

Alias test {

  var %ticks = $ticks

  var %a = 1

  while (%a < 20000) {

     var %check = a

     if (%check = a) var %check = b

     inc %a

  }

  echo -a $calc($ticks - %ticks)

}

This is a simple enough alias, just loops around a couple of thousands of times. This echoed a value of 1094 ticks on my PC.

Now if we take out the contents of the while loop, and put them in a separate alias and then call it, look what happens:

Alias test {

  var %ticks = $ticks

  var %a = 1

  while (%a < 20000) {

    test2

    inc %a

  }

  echo -a $calc($ticks - %ticks)

}

Alias test2 {

  var %check = a

  if (%check = a) var %check = b

}

Now it echoed a value of 1266 ticks. I know it's not a lot, but that's a lot for just calling a single alias that does the exact same thing.

And look what happens if I brake the test2 alias into another alias:

Alias test {

  var %ticks = $ticks

  var %a = 1

  while (%a < 20000) {

    test2

    inc %a

  }

  echo -a $calc($ticks - %ticks)

}

Alias test2 {

  var %check = a

  if (%check = a) test3

}

Alias test3 {

  var %check = b

}

Now it returns 1406 ticks… we lost another 150 ticks just because we called another alias.

Now we see here that at a 20000 loop each alias called adds us about 200 ticks (0.2 seconds or 20% in this example). And that is just for calling the alias, no matter what it contains.

 

 

 

Written by Yochai Timmer  Yochai@Dorot.org.il